# coding:utf-8


class Employee:
    # 类变量，它的值将在这个类的所有实例之间共享。
    # 可以在内部类或外部类使用 Employee.empCount 访问
    empCount = 0

    # __init__()方法是一种特殊的方法
    # 被称为类的构造函数或初始化方法
    # 当创建了这个类的实例时就会调用该方法
    def __init__(self, name, salary):
        self.name = name
        self.salary = salary
        Employee.empCount += 1

    # self 代表类的实例，self在定义类的方法时必须有，虽然在调用时不必传入响应的参数
    @staticmethod
    def displayCount():
        print("Total Employee", Employee.empCount)

    def displayEmployee(self):
        print("Name", self.name, "Salary", self.salary)


# self代表类的实例，而非类
# self不是关键字，换成其他的也可以
class Test:
    def prt(self):
        print(self)
        print(self.__class__)


# 创建实例对象
employee = Employee("buddy", 20)
# 访问属性、方法
employee.displayCount()
Employee.displayEmployee(employee)
# 修改属性
employee.name = "Happy Buddy"
employee.displayEmployee()
print(employee.__getattribute__("name"))
print(employee.__getattribute__("salary"))
employee.__setattr__("home", "beijing")
print(employee.__dict__)
employee.__delattr__("home")
print(employee.__dict__)
print(employee.__module__)

t = Test()
t.prt()

# python使用引用计数这一技术来追踪和回收垃圾
# 在python内部记录着所有使用中的对象各有多少引用
# 一个内部跟踪变量，称为一个引用计数器
# 当对象被创建时，就创建了一个引用计数，档这个对象不在需要，即计数变为0时，就被垃圾回收
# 但回收不是立即的，由解析器在适当的时机，将垃圾对象占用的内存空间回收
a = 40  # 创建对象 <40>
b = a  # 增加引用 <40>的计数
c = [b]  # 增加引用 <40>的计数
del a  # 减少引用 <40>的计数
b = 100  # 减少引用 <40>的计数
c[0] = -1  # 减少引用 <40>的计数


# 垃圾回收机制不仅针对引用计数为0的对象，同样也可以处理循环引用的情况
# 循环引用是指，两个对象互相引用，但没有其他变量引用，这种情况，仅使用引用计数是不够的
# Python的垃圾收集器实际上是一个引用计数器一个循环垃圾收集器
# 作为引用计数的补充，垃圾收集器也会留心被分配的总量很大（及未通过引用计数销毁的）对象
# 在这种情况下，解析器会暂停下来，试图清理所有未被引用的循环

# 实例
class Point:
    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y

    # 析构方法, 删除一个对象
    # 在对象销毁的时候被调用，档对象不在使用时，__del__方法运行
    def __del__(self):
        class_name = self.__class__.__name__
        print(class_name, "销毁")


pt1 = Point()
pt2 = pt1
pt3 = pt1
print(id(pt1), id(pt2), id(pt3))
del pt1
del pt2
del pt3


# 类的继承
class Parent:
    parentAttr = 100

    def __init__(self):
        print("调用父类的构造方法")

    def parentMethod(self):
        print("调用父类的方法")

    def setAttr(self, attr):
        Parent.parentAttr = attr

    def getAttr(self):
        print("父类属性", Parent.parentAttr)


class Child(Parent):
    def __init__(self):
        print("调用子类的构造方法")

    def childMethod(self):
        print("调用子类的方法")


c = Child()
c.childMethod()
c.parentMethod()
c.setAttr(200)
c.getAttr()


# 运算符重载
class Vector:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def __str__(self):
        return 'Vector (%d,%d)' % (self.a, self.b)

    def __add__(self, other):
        return Vector(self.a + other.a, self.b + other.b)


v1 = Vector(2, 10)
v2 = Vector(5, -2)

print(v1 + v2)


# 类的属性与方法
# 类的私有属性
#   __private_attrs：两个下划线开头，声明该属性为私有，不能在外部使用或直接访问
#   在类内部调的方法中使用时 self.__private_attrs
# 类的方法
#   在类的内部，使用def关键字可以为类定义一个方法，与一般函数定义不同，
#   类方法必须包含参数self,且为第一个参数
# 类的私有方法
#    __private_method：两个下划线开头，声明该方法为私有，不能在类的外部调用
#    在类的内部调用self.__private_methods
class JustCounter:
    __secretCount = 0  # 私有变量
    publicCount = 0  # 公开变量

    def count(self):
        self.__secretCount += 1
        self.publicCount += 1
        print("-------------->内部变量：", self.__secretCount)


counter = JustCounter()
counter.count()
counter.count()
print(counter.publicCount)
# python不允许实例化的类访问私有属性，但可以通过object._className__attrName访问属性
print("------------>访问私有变量：", counter._JustCounter__secretCount)

# __foo__ 定义的是特殊方法，一般是系统定义名字，类似__init__()之类的
# _foo 表示protected类型的变量，即保护类型只能允许其本身与子类进行访问
#   不能用于 from module import *
# __foo 双下划线表示私有类型比阿尼两，只能允许这个类进行访问

